package com.cskaoyan.mall.promo.controller;

import com.cskaoyan.mall.common.constant.RedisConst;
import com.cskaoyan.mall.common.constant.ResultCodeEnum;
import com.cskaoyan.mall.common.execption.BusinessException;
import com.cskaoyan.mall.common.result.Result;
import com.cskaoyan.mall.common.util.AuthContext;
import com.cskaoyan.mall.common.util.MD5;
import com.cskaoyan.mall.order.dto.OrderTradeDTO;
import com.cskaoyan.mall.order.query.OrderInfoParam;
import com.cskaoyan.mall.promo.api.dto.SeckillGoodsDTO;
import com.cskaoyan.mall.promo.constant.LocalCacheEnum;
import com.cskaoyan.mall.promo.constant.SeckillCodeEnum;
import com.cskaoyan.mall.promo.service.PromoService;
import com.cskaoyan.mall.promo.task.PromoTask;
import com.cskaoyan.mall.promo.util.LocalCacheHelper;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@RestController
public class PromoController {
    @Autowired
    PromoService promoService;

    @Autowired
    RedissonClient redissonClient;
    @Autowired
    PromoTask promoTask;

    @GetMapping("/seckill")
    public Result<List<SeckillGoodsDTO>> seckill(){
        List<SeckillGoodsDTO> all = promoService.findAll();
        return Result.ok(all);
    }

    @GetMapping("/seckill/{skuId}")
    public Result<SeckillGoodsDTO> getSeckillInfo(@PathVariable Long skuId){
        SeckillGoodsDTO seckillGoodsDTO = promoService.getSeckillGoodsDTO(skuId);
        return Result.ok(seckillGoodsDTO);
    }

    @GetMapping("/seckill/auth/getSeckillSkuIdStr/{skuId}")
    public Result<String> getSeckillSkuIdStr(@PathVariable Long skuId, HttpServletRequest httpServletRequest){
        //先获取对应的userId
        String userId = AuthContext.getUserId(httpServletRequest);
        SeckillGoodsDTO seckillGoodsDTO = promoService.getSeckillGoodsDTO(skuId);
        if (seckillGoodsDTO==null){
            return Result.build(null, ResultCodeEnum.ILLEGAL_REQUEST);
        }
        Long currentTime=new Date().getTime();
        Long beginTime=seckillGoodsDTO.getStartTime().getTime();
        Long endTime=seckillGoodsDTO.getEndTime().getTime();
        if (beginTime<=currentTime&&currentTime<=endTime){
            //生成一个对应的加密令牌
            String encrypted = MD5.encrypt(skuId + userId);
            return Result.ok(encrypted);
        }
        return Result.build(null, ResultCodeEnum.ILLEGAL_REQUEST);

    }

    @GetMapping("seckill/auth/trade/{skuId}")
    public Result trade(@PathVariable Long skuId, @RequestParam String skuIdStr, HttpServletRequest httpServletRequest){
        //这个地方的业务是
        //先判断本地内存中间是否有库存，然后判断令牌是否正确
        //然后在这里组装order信息，但不对数据库内容改变
        String userId = AuthContext.getUserId(httpServletRequest);

        Integer hasStock = (Integer) LocalCacheHelper.get(String.valueOf(skuId));
        if (hasStock!=null&&LocalCacheEnum.NO_STOCK.getCode()==hasStock){
            return Result.build(null, SeckillCodeEnum.SECKILL_FAIL);
        }
        String encrypted = MD5.encrypt(skuId + userId);
        if (!Objects.equals(skuIdStr, encrypted)){
            return Result.build(null, SeckillCodeEnum.SECKILL_ILLEGAL);
        }
        //调用service获取信息
        OrderTradeDTO tradeData = promoService.getTradeData(userId, skuId);
        return Result.ok(tradeData);
    }

    @PostMapping("/seckill/auth/submitOrder")
    public Result submitOrder(@RequestBody OrderInfoParam orderInfoParam,HttpServletRequest httpServletRequest){
        //这个地方的业务逻辑是什么呢？
        //这个地方的业务逻辑是，，先用本地缓存校验库存，，，
        //然后，，，使用redis校验是否已经抢购过了，然后打上抢购标记
        //然后。调用service扣减库存，远程调用order生成订单即可
        String userId = AuthContext.getUserId(httpServletRequest);
        Long skuId = orderInfoParam.getOrderDetailList().get(0).getSkuId();
        Integer hasStock = (Integer) LocalCacheHelper.get(String.valueOf(skuId));
        if (hasStock!=null&&LocalCacheEnum.NO_STOCK.getCode()==hasStock){
            return Result.build(null, SeckillCodeEnum.SECKILL_FAIL);
        }
        //把userId存起来
        orderInfoParam.setUserId(Long.valueOf(userId));
        //然后校验redis
        String key= RedisConst.PROMO_USER_ORDERED_FLAG+skuId+userId;
        RBucket<Object> bucket = redissonClient.getBucket(key);
        boolean existBuy = bucket.trySet(skuId);
        if(!existBuy){
            return Result.build(null, SeckillCodeEnum.SECKILL_DUPLICATE_TRADE);
        }
        //不然就调用service的内容下单
        try{
            boolean result = promoService.submitOrder(orderInfoParam);
            if (!result){
                bucket.delete();
                return Result.build(null, SeckillCodeEnum.SECKILL_FAIL);
            }
        }catch (Exception e){
            e.printStackTrace();
            bucket.delete();
            return Result.build(null, SeckillCodeEnum.SECKILL_FAIL);
        }

        return Result.ok();
    }

    @GetMapping("/seckill/auth/checkOrder/{skuId}")
    public Result checkOrder(@PathVariable Long skuId, HttpServletRequest request) {
        String userId = AuthContext.getUserId(request);
        boolean result = promoService.checkOrder(skuId, userId);
        if (result){
            return Result.build(null, SeckillCodeEnum.SECKILL_SUCCESS);
        }

        return Result.build(null, SeckillCodeEnum.SECKILL_RUN);
    }


    @GetMapping("/seckill/init")
    public Result  init(){
        promoTask.importIntoRedisTsk();
        return Result.ok();
    }

    @GetMapping("/seckill/clear")
    public Result clear(){
        promoTask.finishPromo();
        return Result.ok();
    }


}
